#include "include/cam_control_impl.hpp"
#include <thread>
#include "include/HCNetSDK.h"
#include <cstring>

#ifdef LINUX
//the following are UBUNTU/LINUX ONLY terminal color codes.
#define CONSOLE_COLOR_RESET   "\033[0m"
#define CONSOLE_COLOR_BLACK   "\033[30m"      /* Black */
#define CONSOLE_COLOR_RED     "\033[31m"      /* Red */
#define CONSOLE_COLOR_GREEN   "\033[32m"      /* Green */
#define CONSOLE_COLOR_YELLOW  "\033[33m"      /* Yellow */
#define CONSOLE_COLOR_BLUE    "\033[34m"      /* Blue */
#define CONSOLE_COLOR_MAGENTA "\033[35m"      /* Magenta */
#define CONSOLE_COLOR_CYAN    "\033[36m"      /* Cyan */
#define CONSOLE_COLOR_WHITE   "\033[37m"      /* White */
#define CONSOLE_COLOR_BOLDBLACK   "\033[1m\033[30m"      /* Bold Black */
#define CONSOLE_COLOR_BOLDRED     "\033[1m\033[31m"      /* Bold Red */
#define CONSOLE_COLOR_BOLDGREEN   "\033[1m\033[32m"      /* Bold Green */
#define CONSOLE_COLOR_BOLDYELLOW  "\033[1m\033[33m"      /* Bold Yellow */
#define CONSOLE_COLOR_BOLDBLUE    "\033[1m\033[34m"      /* Bold Blue */
#define CONSOLE_COLOR_BOLDMAGENTA "\033[1m\033[35m"      /* Bold Magenta */
#define CONSOLE_COLOR_BOLDCYAN    "\033[1m\033[36m"      /* Bold Cyan */
#define CONSOLE_COLOR_BOLDWHITE   "\033[1m\033[37m"      /* Bold White */
#endif

//相机的角度参数是十六进制,需要和十进制来回切换
int HexToDecMa(int wHex)//十六进制转十进制
{
    return (wHex / 4096) * 1000 + ((wHex % 4096) / 256) * 100 + ((wHex % 256) / 16) * 10 + (wHex % 16);
}

int DEC2HEX_doc(int x)//十进制转十六进制
{
    return (x / 1000) * 4096 + ((x % 1000) / 100) * 256 + ((x % 100) / 10) * 16 + x % 10;
}

unsigned short hkDecToHex(int src){
    std::string hexStr="0x"+std::to_string(src);
    int dec = std::stoi(hexStr,nullptr,0);
    unsigned short res=dec;
    return res;

}

int hexToDec(int a)
{
    int y = 0;          // 循环中的余数
    std::string s = ""; // 输出的结果
    if (a == 0)         // 0比较特殊，单独处理
    {
        return 0;
    }

    while (a > 0) // 大于0的数
    {
        y = a % 16;                // 求余
        if (y < 10)                // 小于10的余数
            s = char('0' + y) + s; // 利用字符的ascll码在字符串前面拼接
        else
            s = char('A' - 10 + y) + s; // 大于9的余数用ABCDE表示
        a = a / 16;
    }
    return atoi(s.c_str());
}

void CALLBACK G_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{
    char tempbuf[256] = { 0 };
    switch (dwType)
    {
    case EXCEPTION_RECONNECT:    //预览时重连
        std::cout<<"----------reconnect--------"<<time(NULL)<<std::endl;
        break;
    default:
        break;
    }
}

///实时流回调
void CALLBACK G_RealDataCallBack01(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
{
    cam_control_interface::caminfo * dev = (cam_control_interface::caminfo *) pUser;
    switch (dwDataType)
    {
    case NET_DVR_SYSHEAD: //系统头
    break;       
    }
}

REALDATACALLBACK getCallBack(int * camCallBackNum)
{
   
    return G_RealDataCallBack01;
          
     
    
}

cam_control_interface::caminfo cam_control_impl::getLastCamInfo()
{
    if(globalCamInfo.size()>0){
        return globalCamInfo.back();
    }
    return cam_control_interface::caminfo();
}

cam_control_interface::caminfo cam_control_impl::findCamInfo(const char * camId)
{
    if(globalCamInfo.size()>0){
        std::vector<caminfo>::iterator cam;
        for(cam = globalCamInfo.begin();cam!=globalCamInfo.end();cam++){
            if(strcmp((cam)->camId,camId)==0){
                return *cam;
            }
        }
    }
    return cam_control_interface::caminfo();
}

std::vector<cam_control_interface::caminfo> cam_control_impl::getGlobalCamInfo()
{
    return globalCamInfo;
}

int cam_control_impl::addCamInfo(cam_control_interface::caminfo info)
{
    globalCamInfo.push_back(info);
   
    return 0;
}

int cam_control_impl::delCamInfo(const char * camId)
{
    std::vector<caminfo>::iterator cam;
    for(cam = globalCamInfo.begin();cam!=globalCamInfo.end();cam++){
        if(strcmp((cam)->camId,camId)==0){         
            globalCamInfo.erase(cam);
            globalCamInfo.shrink_to_fit();
            return 0; 
        }
    }               
    return -1;   
}

cam_control_interface::caminfo cam_control_impl::findCamInfoBynPort(int & callBackNum)
{
    std::vector<caminfo>::iterator cam;
    for(cam = globalCamInfo.begin();cam!=globalCamInfo.end();cam++){
        if(cam->G_nPORT ==callBackNum){
            return *cam;
        }
    }        
    return caminfo();
}

int cam_control_impl::man_control(const char *camId, const int camSpeed, const int cmd, const int motion)
{
    caminfo cam = findCamInfo(camId);
    std::cout << std::to_string(cmd) << std::endl;
    std::cout << "GUserID: "<<cam.GUserID << std::endl;
    std::cout << "channelId: "<<cam.channelId << std::endl;
    std::cout << "camType: "<<cam.camType << std::endl;
    std::cout << "camSpeed: "<<camSpeed << std::endl;
    std::cout << "motion: "<<motion << std::endl;
    int control_cmd = -1;    
    switch (cmd)
    {
    case UP:
        control_cmd = TILT_UP;
        break;
    case DOWN:
        control_cmd = TILT_DOWN;
        break;
    case LEFT:
        control_cmd = PAN_LEFT;
        break;
    case RIGHT:
        control_cmd = PAN_RIGHT;
        break;
    case ZOOMIN:
        control_cmd = ZOOM_IN;
        break;
    case ZOOMOUT:
        control_cmd = ZOOM_OUT;
        break;
    case UPLEFT:
        control_cmd = UP_LEFT;
        break;
    default:
        break;
    }   
    if (cam.camId != nullptr && cam.camType != 1 && control_cmd>-1)
    {
        // camSpeed = round((double)camSpeed / (double)255 * (double)7); // 海康的速度最大为7
        return NET_DVR_PTZControlWithSpeed_Other(cam.GUserID, (LONG)cam.channelId, control_cmd, motion, camSpeed);
    }   
    return -1;
}

cam_control_interface::caminfo cam_control_impl::camwarp2caminfo(caminfowrap &wrap)
{
    caminfo info;
    info.GUserID=wrap.GUserID;
    info.G_nPORT = wrap.G_nPORT;
    info.callBackNum = wrap.callBackNum;
    info.camId = const_cast<char *>(wrap.camId.c_str());
    info.camIp = const_cast<char *>(wrap.camIp.c_str());
    info.camRealIp = const_cast<char *>(wrap.camRealIp.c_str());
    info.userName = const_cast<char *>(wrap.userName.c_str());
    info.userPwd = const_cast<char *>(wrap.userPwd.c_str());
    info.port = wrap.port;
    info.camType = wrap.camType;
    info.camspeed = wrap.camspeed;
    info.channelId = wrap.channelId;
    info.streamType = wrap.streamType;
    info.camRealPort = wrap.camRealPort;
    info.camRealUserName =  const_cast<char *>(wrap.camRealUserName.c_str());
    info.camRealPwd =  const_cast<char *>(wrap.camRealPwd.c_str());
    info.geoscope =  const_cast<char *>(wrap.geoscope.c_str());//摄像头可视范围

    info.cmosLen =  const_cast<char *>(wrap.cmosLen.c_str());
    info.minFocal = const_cast<char *>(wrap.minFocal.c_str());
    info.northAngle = const_cast<char *>(wrap.northAngle.c_str());
    info.camLongitude = const_cast<char *>(wrap.camLongitude.c_str());
    info.camLatitude = const_cast<char *>(wrap.camLatitude.c_str());
    info.camHeight = const_cast<char *>(wrap.camHeight.c_str());

    info.direction = const_cast<char *>(wrap.direction.c_str());
    info.tOffset = const_cast<char *>(wrap.tOffset.c_str());
    return info;    
}

int cam_control_impl::add_cam_stream(std::string camId)
{
    return 0;
}

std::vector<cam_control_interface::caminfo> cam_control_impl::get_ptr_from_list(std::vector<std::string> camid_list)
{
    return std::vector<cam_control_interface::caminfo>();
}

int cam_control_impl::set_guserid(const char *camId, const int guserid)
{
    if(globalCamInfo.size()>0){
        std::vector<caminfo>::iterator cam;
        for(cam = globalCamInfo.begin();cam!=globalCamInfo.end();cam++){
            if(strcmp((cam)->camId,camId)==0){
                cam->GUserID=guserid;
                return 0;
            }
        }
    } 
    return -1;
}
int cam_control_impl::set_gnport(const char *camId, const int gnport)
{
    if(globalCamInfo.size()>0){
        std::vector<caminfo>::iterator cam;
        for(cam = globalCamInfo.begin();cam!=globalCamInfo.end();cam++){
            if(strcmp((cam)->camId,camId)==0){
                cam->G_nPORT=gnport;
                return 0;
            }
        }
    } 
    return 0;
}
bool cam_control_impl::CaptrueImgNew(const char *camId, const char *filename)
{
    try
    {
        caminfo cam = findCamInfo(camId);
        if(cam.GUserID>=0)
        {
            LPNET_DVR_JPEGPARA JpegPara=new NET_DVR_JPEGPARA;
            JpegPara->wPicQuality=0;
            JpegPara->wPicSize=0;
            std::cout<<cam.channelId<<std::endl;
            int capture = NET_DVR_CaptureJPEGPicture(cam.GUserID,cam.channelId,JpegPara,const_cast<char*>(filename));
            if(capture==false){
                std::cout<<"NET_DVR_CaptureJPEGPicture error\n";
                std::cout<<"%d\n", NET_DVR_GetLastError();
            }
            std::cout<<"图片保存:"<<camId<<std::endl;
        }
    }
    catch(std::exception ex){
        return false;
    }
    return true;
}

void cam_control_impl::PtzControl(const char *camId, const int &pan, const int &tilt, const int &zoom, const int &action)
{
    caminfo cam = findCamInfo(camId);
    //  action:1-定位PTZ参数，2-定位P参数，3-定位T参数，4-定位Z参数，5-定位PT参数
    NET_DVR_PTZPOS ptzpos;
    ptzpos.wAction = action;
    ptzpos.wPanPos = hkDecToHex(pan);
    ptzpos.wTiltPos = hkDecToHex(tilt);
    ptzpos.wZoomPos = hkDecToHex(zoom);
    NET_DVR_SetDVRConfig(cam.GUserID, NET_DVR_SET_PTZPOS, cam.channelId, &ptzpos, sizeof(NET_DVR_PTZPOS));
}

int cam_control_impl::InitCam(const caminfo info)
{
        //---------------------------------------
    if(!sdkIsInit && info.camType!=1){
        SdkInit();
    }

       //---------------------------------------
       // 注册设备       
        NET_DVR_DEVICEINFO_V30 struDeviceInfo;
        LONG GUserID=-5;  
        LPNET_DVR_USER_LOGIN_INFO pLoginInfo = new NET_DVR_USER_LOGIN_INFO;
        pLoginInfo->bUseAsynLogin = 0;
        memcpy(pLoginInfo->sDeviceAddress, info.camIp, NET_DVR_DEV_ADDRESS_MAX_LEN);
        memcpy(pLoginInfo->sUserName, info.userName, NAME_LEN);
        memcpy(pLoginInfo->sPassword, info.userPwd, NAME_LEN);
        pLoginInfo->wPort = info.port;
        LPNET_DVR_DEVICEINFO_V40 lpDeviceInfo = new NET_DVR_DEVICEINFO_V40;
        GUserID = NET_DVR_Login_V40(pLoginInfo,lpDeviceInfo);
        if (GUserID < 0)
        {
            printf("Login error, %d\n", NET_DVR_GetLastError());
            NET_DVR_Cleanup();
            return GUserID;
        }
    //    if(findCamInfo(info.camId)!=NULL){
        //    caminfo * cam=(caminfo *)malloc(sizeof(caminfo));
        //    cam->camId = info.camId;
        //    cam->camIp = info.camIp;
        //    cam->channelId=info.channelId;
        //    cam->port=info.port;
        //    cam->streamType=info.streamType;
        //    cam->userName=info.userName;
        //    cam->userPwd=info.userPwd;
        //    info.GUserID=GUserID;
        //    cam->camspeed=info.camspeed;          
        //    cam->camType=info.camType;
        //    cam->camRealIp=info.camRealIp;
        //    if(getGlobalCamInfo()!=NULL){
        //    addCamInfo(*cam);
        //    }else{
        //        initGlobalCamInfo(*cam);
        //    }

       //printf("%d",GUserID);
       //---------------------------------------
       //设置异常消息回调函数
       NET_DVR_SetExceptionCallBack_V30(0, NULL, G_ExceptionCallBack, NULL);


    // }    
    return GUserID;   
}

bool cam_control_impl::SaveVideoFile(const char *camId, const char *filename,unsigned long videoTime)
{
    caminfo cam = findCamInfo(camId);   
    try{
        if(cam.GUserID>=0 && cam.lRealPlayHandle>=0){
            // start save             
            int videoSaver = NET_DVR_SaveRealData(cam.lRealPlayHandle,const_cast<char*>(filename));
            if(videoSaver==false){
                std::cout<<"NET_DVR_SaveReacamlData error\n";
                std::cout<<"%d\n", NET_DVR_GetLastError();
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(videoTime));
            // end save 
            int endSaver = NET_DVR_StopSaveRealData(cam.lRealPlayHandle);

            std::cout<<"视频文件保存:"<<camId<<std::endl;
        }
    }catch(std::exception ex){
        std::cerr<<ex.what()<<std::endl;
        return false;
    }
    return true;    
}

void cam_control_impl::StartGetStream(caminfo &cam)
{
}

cam_control_interface::camptz<int, int, int> cam_control_impl::get_ptz(const char * camId)
{
    camptz<int, int, int> ptz;
    caminfo cam = findCamInfo(camId);
    NET_DVR_PTZPOS ptzpos;
    DWORD tmp = 0;
    NET_DVR_GetDVRConfig(cam.GUserID, NET_DVR_GET_PTZPOS, (LONG)cam.channelId, &ptzpos, sizeof(NET_DVR_PTZPOS), &tmp);
    ptz.pan = hexToDec(ptzpos.wPanPos);
    ptz.tilt = hexToDec(ptzpos.wTiltPos);
    ptz.zoom = hexToDec(ptzpos.wZoomPos);
    // std::cout<<"获取ptz,camId:"<<camId<<"pan:"<<ptz.pan<<"tilt:"<<ptz.tilt<<"zoom:"<<ptz.zoom<<std::endl;
    return ptz;
    
}

////  action:1-定位PTZ参数，2-定位P参数，3-定位T参数，4-定位Z参数，5-定位PT参数
void cam_control_impl::set_ptz(const char *camId, camptz<int, int, int> &&ptz, int action)
{
    caminfo cam = findCamInfo(camId);
    // if((strcmp(last_control_camId.c_str(),cam->camId) && (last_control_time==0||(util::get_time_stamp()-last_control_time)>1))||!strcmp(last_control_camId.c_str(),cam->camId)){    
    NET_DVR_PTZPOS ptzpos;
    ptzpos.wAction = action;
    ptzpos.wPanPos = hkDecToHex(ptz.pan);
    ptzpos.wTiltPos = hkDecToHex(ptz.tilt);
    ptzpos.wZoomPos = hkDecToHex(ptz.zoom);
    NET_DVR_SetDVRConfig(cam.GUserID, NET_DVR_SET_PTZPOS, (LONG)cam.channelId, &ptzpos, sizeof(NET_DVR_PTZPOS));        

    // }
}

int cam_control_impl::set_last_ptz(const char *camId,camptz<int, int, int> &ptz)
{
    this->camInfoMap[camId]=ptz;
    return 0;
}

const cam_control_interface::camptz<int, int, int> *cam_control_impl::get_last_ptz(const char *camId)
{
    if(this->camInfoMap.find(camId)!=this->camInfoMap.end()){
        return &this->camInfoMap[camId];
    }
    return nullptr;
}

void cam_control_impl::Disconnect(caminfo &cam)
{
}

void cam_control_impl::StartConnect(caminfo &cam)
{
}

void cam_control_impl::SdkInit()
{
    // NET_DVR_LOCAL_SDK_PATH stuSDKPath;
	// memcpy(stuSDKPath.sPath, "/data/hh_vision_lib/video_app/hklib", 36);   
	// if (NET_DVR_SetSDKInitCfg(NET_SDK_INIT_CFG_SDK_PATH, &stuSDKPath))
	// {
    //     std::cerr<<CONSOLE_COLOR_BOLDGREEN<<"NET_DVR_SetSDKInitCfg OK"<<CONSOLE_COLOR_RESET<<std::endl;
	// 	//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "NET_DVR_SetSDKInitCfg OK\n");
	// }
	// else
	// {
    //      std::cerr<<CONSOLE_COLOR_BOLDRED<<"NET_DVR_SetSDKInitCfg Error, ErrorCode ="<<NET_DVR_GetLastError()<<CONSOLE_COLOR_RESET<<std::endl;
	// 	//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NET_DVR_SetSDKInitCfg Error, ErrorCode = %d \n", NET_DVR_GetLastError());
	// }
	if (!NET_DVR_Init()) //init SDK
	{
		std::cerr<<CONSOLE_COLOR_BOLDRED<<"NET_DVR_SetSDKInitCfg Error, ErrorCode ="<<NET_DVR_GetLastError()<<CONSOLE_COLOR_RESET<<std::endl;
	}
    DWORD dVersion = NET_DVR_GetSDKVersion();
    std::cout<<(dVersion >> 16) << (0x0000ffff & dVersion)<<std::endl;
    // 初始化
    // NET_DVR_Init();
    //设置连接时间与重连时间
    NET_DVR_SetConnectTime(2000, 1);
    NET_DVR_SetReconnect(10000, true);
    this->sdkIsInit=true;
}
